#pragma once
#include<iostream>
#include<string>
#include<memory>
#include"Socket.hpp"
#include"Epoller.hpp"
#include "Log.hpp"
using namespace NetWorkModule;
using namespace EpollerModule;
const static int gbacklog=32;


// for debug
std::string EventToString(uint32_t events)
{
    std::string info;
    if (events & EPOLLIN)
        info += "EPOLLIN ";
    if (events & EPOLLOUT)
        info += "EPOLLOUT ";
    if (events & EPOLLET)
        info += "EPOLLET";

    return info;
}

class EpollServer
{
    static const int gmaxevents=64;
    public:
    EpollServer(int port)
    :_listensock(new TcpSocket()),
    _epoller(new Epoller()),
    _port(port),
    _isrunning(false)
    {

    }
    bool InitSrever()
    {
        _listensock->BulidListenSocketMethod(_port,gbacklog);
        lg.LogMessage(Info, "init socket success, listensock is : %d\n", _listensock->GetSockFd());
        _epoller->initEpoller();
        lg.LogMessage(Info, "init epoller success\n");
        //将listensock添加到epoll中
        _epoller->AddEvent(_listensock->GetSockFd(),EPOLLIN);
        return true;
    }
    bool Accepter(std::string *peerip,uint16_t *peerport)
    {
         // 监听事件就绪
        int sockfd=_listensock->AcceptConnection(peerip,peerport);
         if (sockfd < 0)
        {
            lg.LogMessage(Warning, "accept error");
            return false;
        }
         // 获取链接成功
         _epoller->AddEvent(sockfd,EPOLLIN);
         return true;
    }
    int Recver(int sockfd,std::string *out)
    {
        // 真实情况是：每一个sockfd都要有一个自己的输入和输出缓冲区！！！！！
        // 其实是要对sockfd进行封装的，要不然无法把底层fd和上层关联起来！
        char buffer[1024];
        int n=::recv(sockfd,buffer,sizeof(buffer),0);
         if (n > 0)
        {
            buffer[n] = 0;
            *out = buffer;
        }
        return n;
    }
    void HandlerEvent(int n)
    {
        lg.LogMessage(Debug,"%d个 events 已经就绪了\n",n);
        for(int i=0;i<n;i++)
        {
            lg.LogMessage(Debug, "ready fd: %d, Event is: %s\n",_revs[i].data.fd,EventToString(_revs[i].events).c_str());
            int sockfd = _revs[i].data.fd;
            uint32_t events = _revs[i].events;
            if(events&EPOLLIN)
            {
                //读事件分为两种:1.listen 2.normal sockfd
                if(sockfd==_listensock->GetSockFd())
                {
                    std::string clientip;
                    uint16_t clientport;
                    if(!Accepter(&clientip,&clientport))
                    continue;
                    lg.LogMessage(Info, "accept client success, client[%s:%d]\n",
                                  clientip.c_str(), clientport);
                }
                else
                {
                    std::string message;
                    int n = Recver(sockfd, &message);
                    if (n > 0)
                    {
                        std::cout << "client# " << message << std::endl;
                        message.resize(message.size()-strlen("\r\n"));
                        // 直接写 -- TODO
                        std::string echo_message = "echo message: " + message + "\r\n";
                        send(sockfd, echo_message.c_str(), echo_message.size(), 0);
                    }
                    else
                    {
                        if (n == 0)
                        {
                            lg.LogMessage(Info, "client %d close\n", sockfd);
                        }
                        else
                        {
                            lg.LogMessage(Info, "client recv %d error\n", sockfd);
                        }
                         _epoller->DelEvent(sockfd);
                         ::close(sockfd);
                    }
                }

            }
        }
    }

    void Loop()
    {
        _isrunning=true;
        while (_isrunning)
        {
            _epoller->DebugFdList();
            int timeout=1000;
            int n=_epoller->Wait(_revs,gmaxevents,timeout);

            switch (n)
            {
            case 0:
                lg.LogMessage(Debug, "timeout...\n");
                break;
            case -1:
                lg.LogMessage(Error, "epoll wait failed!\n");
                break;
            default:
                // 事件就绪了
                lg.LogMessage(Info, "event happend ... \n");
                HandlerEvent(n);
                break;
            }
        }
        _isrunning=false;
    }
     ~EpollServer()
    {
    }


    private:
    std::shared_ptr<Socket> _listensock;
    std::shared_ptr<Epoller> _epoller;
    int _port;
    bool _isrunning;
    struct epoll_event _revs[gmaxevents];
};
